part of "../framework.dart";

/// 调整Path的尺寸
/// 如果宽高同时存在约束，取最小的那个
extension Resize on Path {
  /// 输入的宽和高是总长度，也就是半径的两倍：直径
  Path resize(double? w, [double? h]) {
    assert(w != null || h != null);
    // 以原点为中心，输入素材的上、下、左、右四边的距离，哪一边最先碰到，就return那一边的比例
    // 1. 由于以原点为中心，所以四边都要除以2（如果不存在，则取无限大，意思是剔除比较）
    final limitW = (w ?? double.infinity) / 2;
    final limitH = (h ?? double.infinity) / 2;
    // 2. 将限制与素材的四边比较，取绝对值，这个值的意思是缩放多少恰好与限制相切
    final bound = getBounds();
    final ratioL = (limitW / bound.left).abs();
    final ratioR = (limitW / bound.right).abs();
    final ratioT = (limitH / bound.top).abs();
    final ratioB = (limitH / bound.bottom).abs();
    // 3. 取最小的绝对值，作为最终缩放比例
    final scale = [ratioL, ratioR, ratioT, ratioB].reduce(min);
    return transform(
      Float64List.fromList(
        [scale, 0, 0, 0, 0, scale, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
      ),
    );
  }

  /// 通常用来做动画
  Path clip([double start = 0, double end = 1]) {
    // 注意，我察觉到computeMetrics()出来的结果只能循环一次
    // 当第二次循环时，好像就会循环空的Iterable
    // 因此将Iterable变成每次都重新运算

    // 假设你想截取路径开头的一部分
    double totalLength = 0;
    for (PathMetric metric in computeMetrics()) {
      totalLength += metric.length;
    }

    double startLength = start * totalLength;
    double endLength = end * totalLength;

    Path partialPath = Path();

    for (PathMetric pathMetric in computeMetrics()) {
      // 如果当前的开始和结束在范围内，则截取path
      // 如何算是"在范围内"？
      // 1. 就是要截取的部分的结尾落在当前段落后
      // 2. 或者截取部分的开头落在当前段落前
      // 两者满足1个，就判定为需要处理、加入的path段落
      if (endLength >= 0 || startLength <= pathMetric.length) {
        final begin = max(startLength, 0.0);
        final end = min(pathMetric.length, endLength);

        partialPath.addPath(pathMetric.extractPath(begin, end), Offset.zero);
      }
      // 计算完每一段时，都让length减少，以移到下一段来计算
      startLength -= pathMetric.length;
      endLength -= pathMetric.length;
    }

    return partialPath;
  }
}
